﻿/**************************************************************
*作者：Leon
*创建时间：2022/4/5 21:50:44
**************************************************************/
using System.Collections.ObjectModel;
using Microsoft.Toolkit.Mvvm.Input;

namespace Lad.DrawProject.Controls;

partial class ScrollViewCanvasViewModel
{
    private IRelayCommand? _CreateNewDiagramCommand;

    public IRelayCommand CreateNewDiagramCommand
    {
        get {
            return _CreateNewDiagramCommand ??= new RelayCommand(() => { this.Items.Clear(); });
        }
    }

    private IRelayCommand? _AddItemCommand;

    public IRelayCommand AddItemCommand
    {
        get {
            return _AddItemCommand ??= new RelayCommand<object>(ExecuteAddItemCommand);
        }
    }

    private IRelayCommand? _DirectAddItemCommand;

    public IRelayCommand DirectAddItemCommand
    {
        get {
            return _DirectAddItemCommand ??= new RelayCommand<object>(ExecuteDirectAddItemCommand);
        }
    }

    private IRelayCommand? _DirectRemoveItemCommand;

    public IRelayCommand DirectRemoveItemCommand
    {
        get {
            return _DirectRemoveItemCommand ??= new RelayCommand<object>(ExecuteDirectRemoveItemCommand);
        }
    }
    private IRelayCommand? _RemoveItemCommand;

    public IRelayCommand RemoveItemCommand
    {
        get {
            return _RemoveItemCommand ??= new RelayCommand<object>(ExecuteRemoveItemCommand);
        }
    }
    private IRelayCommand? _ClearSelectedItemsCommand;

    public IRelayCommand ClearSelectedItemsCommand
    {
        get {
            return _ClearSelectedItemsCommand ??= new RelayCommand(ExecuteClearSelectedItemsCommand);
        }
    }
    private IRelayCommand? _AlignTopCommand;

    public IRelayCommand AlignTopCommand
    {
        get {
            return _AlignTopCommand ??= new RelayCommand(ExecuteAlignTopCommand);
        }
    }
    private IRelayCommand? _AlignVerticalCentersCommand;

    public IRelayCommand AlignVerticalCentersCommand
    {
        get {
            return _AlignVerticalCentersCommand ??= new RelayCommand(ExecuteAlignVerticalCentersCommand);
        }
    }
    private IRelayCommand? _AlignBottomCommand;

    public IRelayCommand AlignBottomCommand
    {
        get {
            return _AlignBottomCommand ??= new RelayCommand(ExecuteAlignBottomCommand);
        }
    }

    private IRelayCommand? _AlignLeftCommand;

    public IRelayCommand AlignLeftCommand
    {
        get {
            return _AlignLeftCommand ??= new RelayCommand(ExecuteAlignLeftCommand);
        }
    }

    private IRelayCommand? _AlignHorizontalCentersCommand;

    public IRelayCommand AlignHorizontalCentersCommand
    {
        get {
            return _AlignHorizontalCentersCommand ??= new RelayCommand(ExecuteAlignHorizontalCentersCommand);
        }
    }

    private IRelayCommand? _AlignRightCommand;

    public IRelayCommand AlignRightCommand
    {
        get {
            return _AlignRightCommand ??= new RelayCommand(ExecuteAlignRightCommand);
        }
    }


    private IRelayCommand? _BringForwardCommand;

    public IRelayCommand BringForwardCommand
    {
        get {
            return _BringForwardCommand ??= new RelayCommand(ExecuteBringForwardCommand);
        }
    }

    private IRelayCommand? _BringToFrontCommand;

    public IRelayCommand BringToFrontCommand
    {
        get {
            return _BringToFrontCommand ??= new RelayCommand(ExecuteBringToFrontCommand);
        }
    }

    private IRelayCommand? _SendBackwardCommand;

    public IRelayCommand SendBackwardCommand
    {
        get {
            return _SendBackwardCommand ??= new RelayCommand(ExecuteSendBackwardCommand);
        }
    }

    private IRelayCommand? _SendToBackCommand;

    public IRelayCommand SendToBackCommand
    {
        get {
            return _SendToBackCommand ??= new RelayCommand(ExecuteSendToBackCommand);
        }
    }

    private IRelayCommand? _DistributeHorizontalCommand;

    public IRelayCommand DistributeHorizontalCommand
    {
        get {
            return _DistributeHorizontalCommand ??= new RelayCommand(ExecuteDistributeHorizontalCommand);
        }
    }

    private IRelayCommand? _DistributeVerticalCommand;

    public IRelayCommand DistributeVerticalCommand
    {
        get {
            return _DistributeVerticalCommand ??= new RelayCommand(ExecuteDistributeVerticalCommand);
        }
    }

    private IRelayCommand? _SelectAllCommand;

    public IRelayCommand SelectAllCommand
    {
        get {
            return _SelectAllCommand ??= new RelayCommand(ExecuteSelectAllCommand);
        }
    }


    private IRelayCommand? _UndoCommand;

    public IRelayCommand UndoCommand
    {
        get {
            return _UndoCommand ??= new RelayCommand(() => ServiceProvider.ActionManager.Undo(),
                ServiceProvider.ActionManager.CanUndo);
        }
    }

    private IRelayCommand? _RedoCommand;
    public IRelayCommand RedoCommand
    {
        get {
            return _RedoCommand ??= new RelayCommand(() => ServiceProvider.ActionManager.Redo(),
                ServiceProvider.ActionManager.CanRedo);
        }
    }
}

partial class ScrollViewCanvasViewModel
{
    ActionManager ActionManager => ServiceProvider.ActionManager;
    #region 布局
    /// <summary>
    /// 执行选择的 DesignerItemViewModelBase 条目 水平分布对齐的命令
    /// 备注：支持撤销
    /// </summary>
    private void ExecuteDistributeHorizontalCommand()
    {
        var selectedItems = (from item in this.SelectedItems.OfType<DesignerItemViewModelBase>()
                            where item.ParentId == Guid.Empty
                            orderby item.Left
                            select item).ToArray();

        if (selectedItems.Length > 1)
        {
            var guid = Guid.NewGuid().ToString();
            ActionManager.DoAction(() => {
                double left = Double.MaxValue;
                double right = Double.MinValue;
                double sumWidth = 0;
                foreach (DesignerItemViewModelBase item in selectedItems)
                {
                    left = Math.Min(left, item.Left);
                    right = Math.Max(right, item.Left + item.Width);
                    sumWidth += item.Width;
                }

                double distance = Math.Max(0, (right - left - sumWidth) / (selectedItems.Count() - 1));
                double offset = selectedItems.First().Left;

                foreach (DesignerItemViewModelBase item in selectedItems)
                {
                    double delta = offset - item.Left;
                    foreach (DesignerItemViewModelBase di in SelectionService.GetGroupMembers(item))
                    {
                        di.SetOldValue(di.Left, nameof(di.Left), guid);
                        di.Left += delta;
                    }
                    offset = offset + item.Width + distance;
                }
            }, () => {
                foreach (DesignerItemViewModelBase item in selectedItems)
                {
                    foreach (DesignerItemViewModelBase di in SelectionService.GetGroupMembers(item))
                    {
                        di.Left = di.GetOldValue<double>(nameof(di.Left), guid);
                    }
                }
            });

        }
    }

    /// <summary>
    /// 执行选择的 DesignerItemViewModelBase 条目 垂直分布对齐的命令
    /// 备注：支持撤销
    /// </summary>
    private void ExecuteDistributeVerticalCommand()
    {
        var selectedItems = (from item in this.SelectedItems.OfType<DesignerItemViewModelBase>()
                            where item.ParentId == Guid.Empty
                            orderby item.Top
                            select item).ToArray();

        if (selectedItems.Length > 1)
        {
            var guid = Guid.NewGuid().ToString();
            ActionManager.DoAction(() => {
                double top = Double.MaxValue;
                double bottom = Double.MinValue;
                double sumHeight = 0;
                foreach (DesignerItemViewModelBase item in selectedItems)
                {
                    top = Math.Min(top, item.Top);
                    bottom = Math.Max(bottom, item.Top + item.Height);
                    sumHeight += item.Height;
                }

                double distance = Math.Max(0, (bottom - top - sumHeight) / (selectedItems.Count() - 1));
                double offset = selectedItems.First().Top;

                foreach (DesignerItemViewModelBase item in selectedItems)
                {
                    double delta = offset - item.Top;
                    foreach (DesignerItemViewModelBase di in SelectionService.GetGroupMembers(item))
                    {
                        di.SetOldValue(di.Top, nameof(di.Top), guid);
                        di.Top += +delta;
                    }
                    offset = offset + item.Height + distance;
                }
            },
            () => {
                foreach (DesignerItemViewModelBase item in selectedItems)
                {
                    foreach (DesignerItemViewModelBase di in SelectionService.GetGroupMembers(item))
                    {
                        di.Top = di.GetOldValue<double>(nameof(di.Top), guid);
                    }
                }
            });
        }
    }



    /// <summary>
    /// 执行选择的 SelectableItemViewModelBase 条目上移一层的命令
    /// 备注：支持撤销
    /// </summary>
    private void ExecuteBringForwardCommand()
    {
        List<SelectableItemViewModelBase> ordered = SelectedItems.OrderByDescending(p => p.ZIndex).ToList();

        List<SelectableItemViewModelBase> changeditems = new();
        var guid = Guid.NewGuid().ToString();

        ActionManager.DoAction(() => {
            int count = this.Items.Count;
            for (int i = 0; i < ordered.Count; i++)
            {
                var item = ordered[i];
                int currentIndex = item.ZIndex;
                int newIndex = Math.Min(count - 1 - i, currentIndex + 1);
                if (currentIndex != newIndex)
                {
                    item.SetOldValue(item.ZIndex, nameof(item.ZIndex), guid);
                    item.ZIndex = newIndex;
                    changeditems.Add(item);

                    foreach (var elm in this.Items.Where(p => p.ZIndex == newIndex))
                    {
                        if (elm != item)
                        {
                            elm.SetOldValue(elm.ZIndex, nameof(elm.ZIndex), guid);
                            elm.ZIndex = currentIndex;
                            changeditems.Add(elm);
                            break;
                        }
                    }
                }
            }
        },() => {
            foreach (var item in changeditems)
            {
                item.ZIndex = item.GetOldValue<int>(nameof(item.ZIndex), guid);
            }
        });
    }

    /// <summary>
    /// 执行选择的 SelectableItemViewModelBase 条目置为顶层的命令
    /// 备注：支持撤销
    /// </summary>
    private void ExecuteBringToFrontCommand()
    {
        List<SelectableItemViewModelBase> selectionSorted = SelectedItems.OrderByDescending(p => p.ZIndex).ToList();
        List<SelectableItemViewModelBase> childrenSorted = Items.OrderByDescending(p => p.ZIndex).ToList();

        List<SelectableItemViewModelBase> changeditems = new();
        var guid = Guid.NewGuid().ToString();

        ActionManager.DoAction(() => {
            int i = childrenSorted.Count - 1;
            int j = childrenSorted.Count - selectionSorted.Count - 1;

            foreach (SelectableItemViewModelBase item in childrenSorted)
            {
                item.SetOldValue(item.ZIndex, nameof(item.ZIndex), guid);
                if (selectionSorted.Contains(item))
                    item.ZIndex = i--;
                else
                    item.ZIndex = j--;
                changeditems.Add(item);
            }
        },() => {
            foreach (var item in changeditems)
            {
                item.ZIndex = item.GetOldValue<int>(nameof(item.ZIndex), guid);
            }
        });
    }

    /// <summary>
    /// 执行选择的 SelectableItemViewModelBase 条目后移一层的命令
    /// 备注：支持撤销
    /// </summary>
    private void ExecuteSendBackwardCommand()
    {
        List<SelectableItemViewModelBase> ordered = this.SelectedItems.OrderBy(p => p.ZIndex).ToList();
        int count = this.Items.Count;

        List<SelectableItemViewModelBase> changeditems = new();
        var guid = Guid.NewGuid().ToString();

        ActionManager.DoAction(() => {
            for (int i = 0; i < ordered.Count; i++)
            {
                var item = ordered[i];
                int currentIndex = item.ZIndex;
                int newIndex = Math.Max(i, currentIndex - 1);
                if (currentIndex != newIndex)
                {
                    item.SetOldValue(item.ZIndex, nameof(item.ZIndex), guid);
                    item.ZIndex = newIndex;
                    changeditems.Add(item);

                    foreach (var elm in this.Items.Where(p => p.ZIndex == newIndex))
                    {
                        if (elm != ordered[i])
                        {
                            elm.SetOldValue(elm.ZIndex, nameof(elm.ZIndex), guid);
                            elm.ZIndex = currentIndex;
                            changeditems.Add(elm);

                            break;
                        }
                    }
                }
            }
        }, () => {
            foreach (var item in changeditems)
            {
                item.ZIndex = item.GetOldValue<int>(nameof(item.ZIndex), guid);
            }
        });
    }

    /// <summary>
    /// 执行选择的 SelectableItemViewModelBase 条目置为底层的命令
    /// 备注：支持撤销
    /// </summary>
    private void ExecuteSendToBackCommand()
    {
        List<SelectableItemViewModelBase> selectionSorted = SelectedItems.OrderByDescending(p => p.ZIndex).ToList();
        List<SelectableItemViewModelBase> childrenSorted = Items.OrderByDescending(p => p.ZIndex).ToList();

        List<SelectableItemViewModelBase> changeditems = new();
        var guid = Guid.NewGuid().ToString();

        ActionManager.DoAction(() => {
            int i = childrenSorted.Count - 1;
            int j = selectionSorted.Count - 1;

            foreach (SelectableItemViewModelBase item in childrenSorted)
            {
                item.SetOldValue(item.ZIndex, nameof(item.ZIndex), guid);
                if (selectionSorted.Contains(item))
                    item.ZIndex = j--;
                else
                    item.ZIndex = i--;
                changeditems.Add(item);
            }
        },() => {
            foreach (var item in changeditems)
            {
                item.ZIndex = item.GetOldValue<int>(nameof(item.ZIndex), guid);
            }
        });
    }





    /// <summary>
    /// 选择的 DesignerItemViewModelBase 条目执行顶部对齐命令
    /// 备注：支持撤销
    /// </summary>
    private void ExecuteAlignTopCommand()
    {
        var selectedItems = this.SelectedItems.OfType<DesignerItemViewModelBase>().ToArray();
       
        if (selectedItems.Length > 1)
        {
            var guid = Guid.NewGuid().ToString();
            ActionManager.DoAction(() => {
                double top = selectedItems.OrderBy(p => p.Top).Select(p => p.Top).FirstOrDefault();

                foreach (DesignerItemViewModelBase item in selectedItems)
                {
                    item.SetOldValue(item.Top, nameof(item.Top), guid);
                    item.Top = top;
                }
            },() => {
                 foreach (DesignerItemViewModelBase item in selectedItems)
                 {
                     item.Top = item.GetOldValue<double>(nameof(item.Top), guid);
                 }
             });
        }
    }

    /// <summary>
    /// 选择的 DesignerItemViewModelBase 条目执行垂直居中对齐命令
    /// 备注：支持撤销
    /// </summary>
    private void ExecuteAlignVerticalCentersCommand()
    {
        var selectedItems = this.SelectedItems.OfType<DesignerItemViewModelBase>().ToArray();
      
        if (selectedItems.Length > 1)
        {
            var guid = Guid.NewGuid().ToString();
            ActionManager.DoAction(() => {
                double mid = selectedItems.Select(p => p.Top + p.Height / 2).Average();

                foreach (DesignerItemViewModelBase item in selectedItems)
                {
                    item.SetOldValue(item.Top, nameof(item.Top), guid);
                    item.Top = mid - item.Height / 2;
                }
            },() => {
                foreach (DesignerItemViewModelBase item in selectedItems)
                {
                    item.Top = item.GetOldValue<double>(nameof(item.Top), guid);
                }
            });
        }
    }

    /// <summary>
    /// 选择的 DesignerItemViewModelBase 条目执行垂直底部对齐命令
    /// 备注：支持撤销
    /// </summary>
    private void ExecuteAlignBottomCommand()
    {
        var selectedItems = this.SelectedItems.OfType<DesignerItemViewModelBase>().ToArray();

        if (selectedItems.Length > 1)
        {
            var guid = Guid.NewGuid().ToString();
            ActionManager.DoAction(() => {
                double top = selectedItems.OrderBy(p => p.Top + p.Height).Select(p => p.Top + p.Height).LastOrDefault();

                foreach (DesignerItemViewModelBase item in selectedItems)
                {
                    item.SetOldValue(item.Top, nameof(item.Top), guid);
                    item.Top = top - item.Height;
                }
            },() => {
                foreach (DesignerItemViewModelBase item in selectedItems)
                {
                    item.Top = item.GetOldValue<double>(nameof(item.Top), guid);
                }
            });
        }
    }

    /// <summary>
    /// 选择的 DesignerItemViewModelBase 条目执行垂直左对齐命令
    /// 备注：支持撤销
    /// </summary>
    private void ExecuteAlignLeftCommand()
    {
        var selectedItems = this.SelectedItems.OfType<DesignerItemViewModelBase>().ToArray();
        
        if (selectedItems.Length > 1)
        {
            var guid = Guid.NewGuid().ToString();
            ActionManager.DoAction(() => {
                double left = selectedItems.OrderBy(p => p.Left).Select(p => p.Left).FirstOrDefault();

                foreach (DesignerItemViewModelBase item in selectedItems)
                {
                    item.SetOldValue(item.Left, nameof(item.Left), guid);
                    item.Left = left;
                }
            },() => {
                foreach (DesignerItemViewModelBase item in selectedItems)
                {
                    item.Left = item.GetOldValue<double>(nameof(item.Left), guid);
                }
            });
        }
    }

    /// <summary>
    /// 选择的 DesignerItemViewModelBase 条目执行水平居中对齐命令
    /// 备注：支持撤销
    /// </summary>
    private void ExecuteAlignHorizontalCentersCommand()
    {
        var selectedItems = this.SelectedItems.OfType<DesignerItemViewModelBase>().ToArray();
        if (selectedItems.Length > 1)
        {
            var guid = Guid.NewGuid().ToString();
            ActionManager.DoAction(() => {
                double mid = selectedItems.Select(p => p.Left + p.Width / 2).Average();

                foreach (DesignerItemViewModelBase item in selectedItems)
                {
                    item.SetOldValue(item.Left, nameof(item.Left), guid);
                    item.Left = mid - item.Width / 2;
                }
            }, () => {
                foreach (DesignerItemViewModelBase item in selectedItems)
                {
                    item.Left = item.GetOldValue<double>(nameof(item.Left), guid);
                }
            });
        }
    }

    /// <summary>
    /// 选择的 DesignerItemViewModelBase 条目执行右对齐命令
    /// 备注：支持撤销
    /// </summary>
    private void ExecuteAlignRightCommand()
    {
        var selectedItems = this.SelectedItems.OfType<DesignerItemViewModelBase>().ToArray();
   
        if (selectedItems.Length > 1)
        {
            var guid = Guid.NewGuid().ToString();
            ActionManager.DoAction(() => {
                double right = selectedItems.OrderBy(p => p.Left + p.Width).Select(p => p.Left + p.Width).LastOrDefault();

                foreach (DesignerItemViewModelBase item in selectedItems)
                {
                    item.SetOldValue(item.Left, nameof(item.Left), guid);
                    item.Left = right - item.Width;
                }
            }, () => {
                foreach (DesignerItemViewModelBase item in selectedItems)
                {
                    item.Left = item.GetOldValue<double>(nameof(item.Left), guid);
                }
            });
        }
    }
    #endregion

    /// <summary>
    /// 选择所有条目
    /// </summary>
    private void ExecuteSelectAllCommand()
    {
        foreach (var item in Items)
        {
            item.IsSelected = true;
        }
    }
    private bool AddVerify(out IEnumerable<SelectableItemViewModelBase> items,object? parameter)
    {
        items = Enumerable.Empty<SelectableItemViewModelBase>();
        if (parameter == null) return false;

        // 遍历类型实现的所有接口，判断是否存在某个接口是泛型，且是参数中指定的原始泛型的实例。
        if( parameter.GetType().GetInterfaces()
            .Any(x => typeof(IEnumerable<>) == (x.IsGenericType ? x.GetGenericTypeDefinition() : x)))
        {
            if (parameter is IEnumerable<SelectableItemViewModelBase> objs)
            {
                items = objs;
                return objs.Select(p => AddVerify(p)).Any();
            }
        }
        else if(parameter is SelectableItemViewModelBase obj)
        {
            items = new[] { obj };
            return AddVerify(obj);
        }
        return false;
    }

    /// <summary>
    /// 添加条目命令
    /// 备注：添加单个对象，或者List集合，支持撤销
    /// </summary>
    /// <param name="parameter"></param>
    private void ExecuteAddItemCommand(object? parameter)
    {
        if (AddVerify(out var items, parameter))
        {
            ActionManager.DoAction(() => {
                ClearSelectedItems();
                foreach (var item in items)
                    Add(item);
            }, () => {
                foreach (var item in items)
                    Items.Remove(item);
            });
        }
    }

    /// <summary>
    /// 直接添加条目
    /// 备注：添加单个对象，或者List集合，不支持撤销
    /// </summary>
    /// <param name="parameter"></param>
    private void ExecuteDirectAddItemCommand(object? parameter)
    {
        if (AddVerify(out var items, parameter))
        {
            ClearSelectedItems();
            foreach (var item in items)
                Add(item);
        }
    }


    /// <summary>
    /// 移除条目
    /// 备注：移除单个条目，或者移除List集合，同时移除撤销管理
    /// </summary>
    /// <param name="parameter"></param>
    private void ExecuteRemoveItemCommand( object? parameter)
    {
        parameter ??= SelectedItems.ToArray();
        if (AddVerify(out var items, parameter))
        {
            ActionManager.DoAction(() => {
                foreach (var item in items)
                {
                    item.IsSelected = false;
                    Items.Remove(item);
                    //if (item.OutTextItem != null)
                    //    Items.Remove(item.OutTextItem);
                }
            }, () => {
                foreach (var item in items)
                {
                    Items.Add(item);
                    //if (item.OutTextItem != null)
                    //    Items.Add(item.OutTextItem);
                }
            });
        }
    }

    /// <summary>
    /// 直接移除条目
    /// 备注：移除单个条目，或者移除List集合，不进行撤销管理
    /// </summary>
    /// <param name="parameter"></param>
    private void ExecuteDirectRemoveItemCommand(object? parameter)
    {
        parameter ??= SelectedItems.ToArray();
        if (AddVerify(out var items, parameter))
        {
            foreach (var item in items)
            {
                item.IsSelected = false;
                Items.Remove(item);
                //if (item.OutTextItem != null)
                //    Items.Remove(item.OutTextItem);
            }
        }

    }

    /// <summary>
    /// 执行 ClearSelectedItems() 方法
    /// </summary>
    private void ExecuteClearSelectedItemsCommand()
    {
        ClearSelectedItems();
    }

    /// <summary>
    /// 清空选择条目
    /// </summary>
    public void ClearSelectedItems()
    {
        foreach (var item in this.Items.ToList())
        {
            item.IsSelected = false;
        }
    }


    /// <summary>
    /// SelectableItemViewModelBase的数据验证 
    /// 备注：调用 InitData()进行验证，调用OutAddVerify验证委托进行验证
    /// </summary>
    /// <param name="item"></param>
    /// <returns></returns>
    public bool AddVerify(SelectableItemViewModelBase item)
    {
        if (item.InitData() == false)
            return false;

        if (OutAddVerify != null && OutAddVerify(item) != true)
            return false;

        return true;
    }
}
